package edu.tongji.structureplayer.ui 
{
    
    import edu.tongji.structureplayer.structure.StructureNames;
    import edu.tongji.structureplayer.structure.WellBehavedStructure;
    import edu.tongji.structureplayer.core.errors.ParseStructureError;
    
    import mx.controls.Alert;
    import mx.core.FlexGlobals;
    
    import org.as3commons.collections.LinkedList;
    import org.as3commons.collections.framework.ILinkedList;
    import org.as3commons.collections.framework.ILinkedListIterator;
    import org.as3commons.lang.StringBuffer;
    
    import spark.components.RichEditableText;
    import spark.events.TextOperationEvent;
    
    /**
    * Interpreter takes user's text input, and translates it into XML-based
    * defination file for a structure that is to be solved.
    */ 
    public class InterpreterClassic 
    {
        
        private var _richEditableText:RichEditableText;
        private var _commands:ILinkedList;
        private var testReg:RegExp;
        private var nodeReg:RegExp;

        public function get commands():ILinkedList
        {
            return _commands;
        }

        public function set commands(value:ILinkedList):void
        {
            _commands = value;
        }

        public function get richEditableText():RichEditableText
        {
            return _richEditableText;
        }

        public function set richEditableText(value:RichEditableText):void
        {
            _richEditableText = value;
        }
        
        public function init():void 
        {
            FlexGlobals.topLevelApplication.addElement(_richEditableText);
            _richEditableText = richEditableText;
            _richEditableText.addEventListener(TextOperationEvent.CHANGE, textChangeHandler);
            
            
            _commands = new LinkedList();
            
            initRegExp();
        }
        
        private function initRegExp():void
        {
            var float:String = "[+-]?([1-9][0-9]*|0)(\.[0-9]+)?";
            var word:String = "[a-zA-Z_][a-zA-Z_0-9]*";
            testReg = new RegExp("\\(");
            nodeReg = new RegExp("^" + StructureNames.NODE + "\:" 
                + word + "\\(" + float + "," + float + "\\)$");
        }
        
        public function textChangeHandler(event:TextOperationEvent):void 
        {
            /*Alert.show(_richEditableText.text);*/
            var commands:Array = _richEditableText.text.split('\n');
            setCommandsList(commands);
            var structure:WellBehavedStructure = generateWellBehavedStructure();
            if (null != structure && _commands.last == StructureNames.END)
            {}
        }
        
        private function generateWellBehavedStructure():WellBehavedStructure
        {
            if (_commands.size == 0)return null;
            
            var structure:WellBehavedStructure = new WellBehavedStructure();
            try
            {
                parse(structure);
            }
            catch (error:ParseStructureError)
            {
                trace(error.message);
                return null;
            }
            
            return structure;
            
        }
        
        private function parse(structure:WellBehavedStructure):void
        {
            if (null == structure)return;
            
            var lli : ILinkedListIterator = _commands.iterator() as ILinkedListIterator;
            for (var i:uint=0; lli.hasNext(); i++) 
            {
                lli.next();
                parseLine(lli.current as String);
            }
        }
        
        private function parseLine(str:String):void
        {
            trace(str + ":" + nodeReg.test(str));
        }
        
        private function setCommandsList(commands:Array):void
        {
            if (null == commands) return;
            
            _commands.clear();
            for (var i:uint=0; i<commands.length; i++)
            {
                if (null == commands[i] || isEmpty(commands[i]))
                {
                    continue;
                }
                _commands.addLast(clearSpace(commands[i] as String));
            }

/*            var lli : ILinkedListIterator = _commands.iterator() as ILinkedListIterator;
            trace (lli.previousItem + " [" + lli.current + "] " + lli.nextItem);
            for (var i:uint=0; lli.hasNext(); i++) {
                lli.next();
                trace (i + ":" + lli.previousItem + " [" + lli.current + "] " + lli.nextItem);
            }*/
        }
        
        private function clearSpace(str:String):String
        {
            if (null == str || str.length == 0)
                return "";
            
            var buf:StringBuffer = new StringBuffer();
            for (var i:uint=0; i<str.length; i++)
            {
                if (str.charAt(i)!=" ")
                    buf.append(str.charAt(i));
            }
            return buf.toString();
        }
        
        private function isEmpty(str:String):Boolean
        {
            if (null == str)return true;
            
            var marker:Boolean = false;
            for (var i:uint=0; i<str.length; i++)
            {
                var c:String = str.charAt(i);
                if (c!=' ' && c!='\t' && c!='\n')
                {
                    marker = true;
                    break;
                }
            }
            return !marker;
        }

    }
}